home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume10 / ppmtoxpm < prev    next >
Encoding:
Text File  |  1990-02-20  |  24.4 KB  |  669 lines

  1. Newsgroups: comp.sources.misc
  2. from: mark%zok@sj.ate.slb.com (Mark W. Snitily)
  3. subject: v10i079: ppmtoxpm -- new pbmplus utility
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 79
  7. Submitted-by: mark%zok@sj.ate.slb.com (Mark W. Snitily)
  8. Archive-name: ppmtoxpm
  9.  
  10. This is a program that converts images from the ppm (portable pixmap)
  11. format to the XPM format.  See XPM.README and ppmtoxpm.1 for details.
  12.  
  13. -- Mark
  14.  
  15. Mark W. Snitily                 Consulting Services:
  16. 894 Brookgrove Lane             Graphics, Operating Systems, Compilers
  17. Cupertino, CA 95014             (408) 252-0456
  18. mark@zok.uucp
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 1 (of 1)."
  27. # Contents:  XPM.README ppmtoxpm.1 ppmtoxpm.c
  28. # Wrapped by mark@zok on Sun Feb 18 15:57:59 1990
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'XPM.README' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'XPM.README'\"
  32. else
  33. echo shar: Extracting \"'XPM.README'\" \(4438 characters\)
  34. sed "s/^X//" >'XPM.README' <<'END_OF_FILE'
  35. XMost of you are familiar with Jef Poskanzer's pbmplus utilities.
  36. XFor those of you who are not, they are a wonderful collection of
  37. Xroutines which transform images from one format to another.  This
  38. Xpackage is distributed on the X11R4 contrib tape and can be found
  39. Xon many archive sites.
  40. X
  41. XA relatively new format is XPM whose origins can be traced back to the
  42. Xpeople at Groupe Bull -- the same wonderful folks who brought you the
  43. Xgwm window manager.
  44. X
  45. XThis article contains the source and man page for a "ppmtoxpm" tool
  46. Xwhich transforms an image from the ppm (portable pixmap) format, found
  47. Xin the pbmplus utilities, to the XPM format.
  48. X
  49. XXPM is an ASCII based *color* pixmap format.  It's similar to the XBM
  50. Xformat in that it can be #include'd in C source code, or read from a file
  51. Xat run time.  An example is probably worth a thousand words; the X11
  52. Xbitmap file ".../include/X11/bitmaps/dot" looks like:
  53. X
  54. X#define dot_width 16
  55. X#define dot_height 16
  56. Xstatic char dot_bits[] = {
  57. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xf0, 0x0f, 0xf0, 0x0f,
  58. X   0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f,
  59. X   0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  60. X
  61. XThe same file in XPM format would be:
  62. X
  63. X#define dot_format 1
  64. X#define dot_width  16
  65. X#define dot_height 16
  66. X#define dot_ncolors 2
  67. X#define dot_chars_per_pixel 1
  68. Xstatic char *dot_colors[] = {
  69. X   "`", "black",
  70. X   "a", "white"
  71. X};
  72. Xstatic char *dot_pixels[] = {
  73. X"aaaaaaaaaaaaaaaa",
  74. X"aaaaaaaaaaaaaaaa",
  75. X"aaaaaaaaaaaaaaaa",
  76. X"aaaaaa````aaaaaa",
  77. X"aaaa````````aaaa",
  78. X"aaaa````````aaaa",
  79. X"aaa``````````aaa",
  80. X"aaa``````````aaa",
  81. X"aaa``````````aaa",
  82. X"aaa``````````aaa",
  83. X"aaaa````````aaaa",
  84. X"aaaa````````aaaa",
  85. X"aaaaaa````aaaaaa",
  86. X"aaaaaaaaaaaaaaaa",
  87. X"aaaaaaaaaaaaaaaa",
  88. X"aaaaaaaaaaaaaaaa"
  89. X};
  90. X
  91. XAlthough the above example only uses two colors, XPM files can have an
  92. Xarbitrary number of colors.  Colors can be specified by using either the
  93. Xcolor name mnemonics found in the X11 server's RGB database (e.g. "black"),
  94. Xor the X11 hexadecimal #RGB, ..., #RRRRGGGGBBBB convention.
  95. X
  96. XA good example of a program that understands XPM format is "xloadimage"
  97. X(a.k.a. "xview" and "xsetbg") by Jim Frost (jimf@saber.com).  This program
  98. Xis on the X11R4 contrib tape and has also been posted on comp.sources.x.
  99. X"xloadimage" requires patchlevel 3 to correctly understand the XPM format.
  100. XThis patchlevel should be posted on comp.sources.x in the near future.  In
  101. Xthe mean while, you can obtain a patchlevel 3 version of "xloadimage" via
  102. Xftp from expo.lcs.mit.edu (18.30.0.212) [/contrib/xloadimage.1.03.tar.Z],
  103. Xor via uucp from zok [/usrX/contrib/xldim103.tar.Z].  (BTW, "xloadimage"
  104. Xhas also been tested on unusual X11 servers, those that only have 2 or
  105. X4 bitplanes.)
  106. X
  107. XAfter you unshar the ppmtoxpm.c and ppmtoxpm.1 files, place them into your
  108. X.../pbmplus/ppm directory.  The .../pbmplus/ppm/Imakefile can be updated
  109. Xby applying the following patch:
  110. X
  111. X*** Imakefile.org    Tue Nov 21 22:24:43 1989
  112. X--- Imakefile    Sun Feb 18 14:34:59 1990
  113. X***************
  114. X*** 28,34 ****
  115. X  PORTBINARIES =    giftoppm ilbmtoppm imgtoppm mtvtoppm ppmarith ppmconvol \
  116. X          ppmcscale ppmhist ppmquant ppmscale ppmtogif ppmtoilbm \
  117. X          ppmtopgm ppmtops ppmtorast ppmtoxwd qrttoppm rasttoppm \
  118. X!         tgatoppm xwdtoppm
  119. X  MATHBINARIES =    ppmpat ppmrotate ppmshear
  120. X  BINARIES =    $(PORTBINARIES) $(MATHBINARIES)
  121. X  
  122. X--- 28,34 ----
  123. X  PORTBINARIES =    giftoppm ilbmtoppm imgtoppm mtvtoppm ppmarith ppmconvol \
  124. X          ppmcscale ppmhist ppmquant ppmscale ppmtogif ppmtoilbm \
  125. X          ppmtopgm ppmtops ppmtorast ppmtoxwd qrttoppm rasttoppm \
  126. X!         tgatoppm xwdtoppm ppmtoxpm
  127. X  MATHBINARIES =    ppmpat ppmrotate ppmshear
  128. X  BINARIES =    $(PORTBINARIES) $(MATHBINARIES)
  129. X  
  130. X***************
  131. X*** 36,42 ****
  132. X          ppmconvol.1 ppmcscale.1 ppmhist.1 ppmpat.1 ppmquant.1 \
  133. X          ppmrotate.1 ppmscale.1 ppmshear.1 ppmtogif.1 ppmtoilbm.1 \
  134. X          ppmtopgm.1 ppmtops.1 ppmtorast.1 ppmtoxwd.1 qrttoppm.1 \
  135. X!         rasttoppm.1 tgatoppm.1 xwdtoppm.1
  136. X  MANUALS3 =    libppm.3
  137. X  MANUALS5 =    ppm.5
  138. X  
  139. X--- 36,42 ----
  140. X          ppmconvol.1 ppmcscale.1 ppmhist.1 ppmpat.1 ppmquant.1 \
  141. X          ppmrotate.1 ppmscale.1 ppmshear.1 ppmtogif.1 ppmtoilbm.1 \
  142. X          ppmtopgm.1 ppmtops.1 ppmtorast.1 ppmtoxwd.1 qrttoppm.1 \
  143. X!         rasttoppm.1 tgatoppm.1 xwdtoppm.1 ppmtoxpm.1
  144. X  MANUALS3 =    libppm.3
  145. X  MANUALS5 =    ppm.5
  146. X
  147. X  
  148. XEnjoy.
  149. X
  150. X-- Mark
  151. X
  152. XMark W. Snitily                 Consulting Services:
  153. X894 Brookgrove Lane             Graphics, Operating Systems, Compilers
  154. XCupertino, CA 95014             (408) 252-0456
  155. Xmark@zok.uucp
  156. END_OF_FILE
  157. if test 4438 -ne `wc -c <'XPM.README'`; then
  158.     echo shar: \"'XPM.README'\" unpacked with wrong size!
  159. fi
  160. # end of 'XPM.README'
  161. fi
  162. if test -f 'ppmtoxpm.1' -a "${1}" != "-c" ; then 
  163.   echo shar: Will not clobber existing file \"'ppmtoxpm.1'\"
  164. else
  165. echo shar: Extracting \"'ppmtoxpm.1'\" \(2447 characters\)
  166. sed "s/^X//" >'ppmtoxpm.1' <<'END_OF_FILE'
  167. X.TH ppmtoxpm 1 "13 February 1990"
  168. X.SH NAME
  169. Xppmtoxpm - convert a portable pixmap into an X11 pixmap
  170. X.SH SYNOPSIS
  171. Xppmtoxpm [-name <xpmname>] [-rgb <rgb-textfile>] [<ppmfile>]
  172. X.SH DESCRIPTION
  173. XReads a portable pixmap as input.
  174. XProduces X11 pixmap (XPM) as output.
  175. X.PP
  176. XThe -name option allows one to specify the prefix string which is printed
  177. Xin the resulting XPM output.  If not specified, will default to the
  178. Xfilename (without extension) of the <ppmfile> argument.
  179. XIf -name is not specified and <ppmfile>
  180. Xis not specified (i.e. piped input), the prefix string will default to
  181. Xthe string "noname".
  182. X.PP
  183. XThe -rgb option allows one to specify an X11 rgb text file for the
  184. Xlookup of color name mnemonics.  This rgb text file is typically the
  185. X/usr/lib/X11/rgb.txt of the MIT X11 distribution, but any file using the
  186. Xsame format may be used.  When specified and
  187. Xa RGB value from the ppm input matches a RGB value from the <rgb-textfile>,
  188. Xthen the corresponding color name mnemonic is printed in the XPM's colormap.
  189. XIf -rgb is not specified, or if the RGB values don't match, then the color
  190. Xwill be printed with the #RGB, #RRGGBB, #RRRGGGBBB, or #RRRRGGGGBBBB
  191. Xhexadecimal format.
  192. X.PP
  193. XAll flags can be abbreviated to their shortest unique prefix.
  194. X.PP
  195. XFor example, to convert the file "dot" (found in /usr/include/X11/bitmaps),
  196. Xfrom xbm to xpm one could specify
  197. X.IP
  198. Xxbmtopbm dot | ppmtoxpm -name dot
  199. X.PP
  200. Xor, with a rgb text file (in the local directory)
  201. X.IP
  202. Xxbmtopbm dot | ppmtoxpm -name dot -rgb rgb.txt
  203. X.SH BUGS
  204. XAn option to match the closest (rather than exact) color name mnemonic
  205. Xfrom the rgb text would be a desirable enhancement.
  206. X.PP
  207. XTruncation of the least significant bits of a RGB value may result in
  208. Xnonexact matches when performing color name mnemonic lookups.
  209. X.SH "SEE ALSO"
  210. Xppm(5), xloadimage(1) patchlevel 3 by Jim Frost, jimf@saber.com
  211. X.SH AUTHOR
  212. XCopyright (C) 1990 by Mark W. Snitily.
  213. X
  214. XPermission to use, copy, modify, and distribute this software and its
  215. Xdocumentation for any purpose and without fee is hereby granted, provided
  216. Xthat the above copyright notice appear in all copies and that both that
  217. Xcopyright notice and this permission notice appear in supporting
  218. Xdocumentation.  This software is provided "as is" without express or
  219. Ximplied warranty.
  220. X
  221. XThis tool was developed for Schlumberger Technologies, ATE Division, and
  222. Xwith their permission is being made available to the public with the above
  223. Xcopyright notice and permission notice.
  224. END_OF_FILE
  225. if test 2447 -ne `wc -c <'ppmtoxpm.1'`; then
  226.     echo shar: \"'ppmtoxpm.1'\" unpacked with wrong size!
  227. fi
  228. # end of 'ppmtoxpm.1'
  229. fi
  230. if test -f 'ppmtoxpm.c' -a "${1}" != "-c" ; then 
  231.   echo shar: Will not clobber existing file \"'ppmtoxpm.c'\"
  232. else
  233. echo shar: Extracting \"'ppmtoxpm.c'\" \(14877 characters\)
  234. sed "s/^X//" >'ppmtoxpm.c' <<'END_OF_FILE'
  235. X/* ppmtoxpm.c - read a portable pixmap and produce a X11 pixmap
  236. X**
  237. X** Copyright (C) 1990 by Mark W. Snitily
  238. X**
  239. X** Permission to use, copy, modify, and distribute this software and its
  240. X** documentation for any purpose and without fee is hereby granted, provided
  241. X** that the above copyright notice appear in all copies and that both that
  242. X** copyright notice and this permission notice appear in supporting
  243. X** documentation.  This software is provided "as is" without express or
  244. X** implied warranty.
  245. X**
  246. X** This tool was developed for Schlumberger Technologies, ATE Division, and
  247. X** with their permission is being made available to the public with the above
  248. X** copyright notice and permission notice.
  249. X**
  250. X*/
  251. X
  252. X#include <stdio.h>
  253. X#include <ctype.h>
  254. X#include "ppm.h"
  255. X#include "ppmcmap.h"
  256. X
  257. X#ifdef SYSV
  258. X#include <string.h>
  259. X#define index strchr
  260. X#else /*SYSV*/
  261. X#include <strings.h>
  262. X#endif /*SYSV*/
  263. X
  264. X/* Max number of colors allowed in ppm input. */
  265. X#define MAXCOLORS    256
  266. X
  267. X/* Max number of rgb mnemonics allowed in rgb text file. */
  268. X#define MAX_RGBNAMES 1024
  269. X
  270. X/* Lower bound and upper bound of character-pixels printed in XPM output.
  271. X   Be careful, don't want the character '"' in this range. */
  272. X/*#define LOW_CHAR  '#'  <-- minimum ascii character allowed */
  273. X/*#define HIGH_CHAR '~'  <-- maximum ascii character allowed */
  274. X#define LOW_CHAR  '`'
  275. X#define HIGH_CHAR 'z'
  276. X
  277. X#define max(a,b) ((a) > (b) ? (a) : (b))
  278. X
  279. Xvoid read_rgb_names();  /* forward reference */
  280. Xvoid gen_cmap();        /* forward reference */
  281. X
  282. Xtypedef struct {  /* rgb values and ascii names (from rgb text file) */
  283. X   int  r, g, b;  /* rgb values, range of 0 -> 65535 */
  284. X   char *name;    /* color mnemonic of rgb value */
  285. X} rgb_names;
  286. X
  287. Xtypedef struct {  /* character-pixel mapping */
  288. X   char *cixel;   /* character string printed for pixel */
  289. X   char *rgbname; /* ascii rgb color, either color mnemonic or #rgb value */
  290. X} cixel_map;
  291. X
  292. Xpixel **pixels;
  293. X
  294. Xmain(argc, argv)
  295. Xint argc;
  296. Xchar *argv[];
  297. X{
  298. X   FILE *ifd;
  299. X   register pixel *pP;
  300. X   int argn, rows, cols, ncolors, row, col, i;
  301. X   pixval maxval;  /* pixval == unsigned char or unsigned short */
  302. X   colorhash_table  cht;
  303. X   colorhist_vector chv;
  304. X
  305. X   /* Used for rgb value -> rgb mnemonic mapping */
  306. X   int map_rgb_names = 0;
  307. X   rgb_names rgbn[MAX_RGBNAMES];
  308. X   int rgbn_max;
  309. X
  310. X   /* Used for rgb value -> character-pixel string mapping */
  311. X   cixel_map cmap[MAXCOLORS];
  312. X   int charspp; /* chars per pixel */
  313. X
  314. X   char out_name[100], rgb_fname[100], *cp;
  315. X   char *usage = "[-name <xpm-name>] [-rgb <rgb-textfile>] [ppmfile]";
  316. X
  317. X   pm_progname = argv[0];
  318. X   out_name[0] = rgb_fname[0] = '\0';
  319. X
  320. X   argn = 1;
  321. X
  322. X   /* Check for command line options. */
  323. X   while (argn < argc && argv[argn][0] == '-') {
  324. X
  325. X      /* Case "-", use stdin for input. */
  326. X      if (argv[argn][1] == '\0') break;
  327. X
  328. X      /* Case "-name <xpm-filename>", get output filename. */
  329. X      if (strncmp(argv[argn], "-name", max(strlen(argv[argn]),2)) == 0) {
  330. X         argn++;
  331. X         if (argn == argc || sscanf(argv[argn], "%s", out_name) != 1)
  332. X            pm_usage(usage);
  333. X      }
  334. X
  335. X      /* Case "-rgb <rgb-filename>", get rgb mnemonics filename. */
  336. X      else if (strncmp(argv[argn], "-rgb", max(strlen(argv[argn]),2)) == 0) {
  337. X         argn++;
  338. X         if (argn == argc || sscanf(argv[argn], "%s", rgb_fname) != 1)
  339. X            pm_usage(usage);
  340. X         map_rgb_names = 1;
  341. X      }
  342. X
  343. X      /* Nothing else allowed... */
  344. X      else
  345. X         pm_usage(usage);
  346. X
  347. X      argn++;
  348. X   }
  349. X
  350. X   /* Input file specified, open it and set output filename if necessary. */
  351. X   if (argn < argc) {
  352. X
  353. X      /* Open the input file. */
  354. X      ifd = pm_openr(argv[argn]);
  355. X
  356. X      /* If output filename not specified, use input filename as default. */
  357. X      if (out_name[0] == '\0') {
  358. X         strcpy(out_name, argv[argn]);
  359. X         if (cp = index(out_name, '.')) *cp = '\0'; /* remove extension */
  360. X      }
  361. X
  362. X      /* If (1) input file was specified as "-" we're using stdin, or
  363. X            (2) output filename was specified as "-",
  364. X         set output filename to the default. */
  365. X      if (!strcmp(out_name, "-" )) strcpy(out_name, "noname");
  366. X
  367. X      argn++;
  368. X   }
  369. X
  370. X   /* No input file specified.  Using stdin so set default output filename. */
  371. X   else {
  372. X      ifd = stdin;
  373. X      if (out_name[0] == '\0') strcpy(out_name, "noname");
  374. X   }
  375. X
  376. X   /* Only 0 or 1 input files allowed. */
  377. X   if (argn != argc) pm_usage(usage);
  378. X
  379. X   /* "maxval" is the largest value that can be be found in the ppm file.
  380. X      All pixel components are relative to this value. */
  381. X   pixels = ppm_readppm(ifd, &cols, &rows, &maxval);
  382. X   pm_close(ifd);
  383. X
  384. X   /* Figure out the colormap. */
  385. X   fprintf(stderr, "(Computing colormap...");  fflush(stderr);
  386. X   chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &ncolors);
  387. X   if (chv == (colorhist_vector) 0)
  388. X      pm_error(
  389. X         "too many colors - try running the pixmap through 'ppmquant 256'",
  390. X          0, 0, 0, 0, 0);
  391. X   fprintf(stderr, "  Done.  %d colors found.)\n", ncolors);
  392. X
  393. X   /* Make a hash table for fast color lookup. */
  394. X   cht = ppm_colorhisttocolorhash(chv, ncolors);
  395. X
  396. X   /* If a rgb text file was specified, read in the rgb mnemonics.
  397. X      Does not return if fatal error occurs. */
  398. X   if (map_rgb_names) read_rgb_names(rgb_fname, rgbn, &rgbn_max);
  399. X
  400. X   /* Now generate the character-pixel colormap table. */
  401. X   gen_cmap(chv, ncolors, maxval, map_rgb_names, rgbn, rgbn_max,
  402. X            cmap, &charspp);
  403. X
  404. X   /* Write out the XPM header. */
  405. X   printf("#define %s_format %d\n",          out_name, 1);
  406. X   printf("#define %s_width  %d\n",          out_name, cols);
  407. X   printf("#define %s_height %d\n",          out_name, rows);
  408. X   printf("#define %s_ncolors %d\n",         out_name, ncolors);
  409. X   printf("#define %s_chars_per_pixel %d\n", out_name, charspp);
  410. X
  411. X   /* Write out the ascii colormap. */
  412. X   printf("static char *%s_colors[] = {\n", out_name);
  413. X   for (i=0; i<ncolors; i++) {
  414. X      printf("   \"%s\", \"%s\"", cmap[i].cixel, cmap[i].rgbname);
  415. X      if (i != (ncolors - 1)) printf(",\n");
  416. X      else                    printf("\n"); 
  417. X   }     
  418. X   printf("};\n");
  419. X
  420. X   /* Write out the ascii character-pixel image. */
  421. X   printf("static char *%s_pixels[] = {\n", out_name);
  422. X   for (row=0;  row<rows;  row++) {
  423. X      printf("\"");
  424. X      for (col=0, pP=pixels[row];  col<cols;  col++, pP++)
  425. X         printf("%s", cmap[ppm_lookupcolor(cht, *pP)].cixel);
  426. X      if (row != (rows - 1)) printf("\",\n");
  427. X      else                   printf("\"\n"); 
  428. X   }
  429. X   printf("};\n");
  430. X
  431. X   exit(0);
  432. X
  433. X} /* main */
  434. X
  435. X/*---------------------------------------------------------------------------*/
  436. X/* This routine reads a rgb text file.  It stores the rgb values (0->65535)
  437. X   and the rgb mnemonics (malloc'ed) into the "rgbn" array.  Returns the
  438. X   number of entries stored in "rgbn_max". */
  439. Xvoid read_rgb_names(rgb_fname, rgbn, rgbn_max)
  440. Xchar *rgb_fname;
  441. Xrgb_names rgbn[MAX_RGBNAMES];
  442. Xint *rgbn_max;
  443. X{
  444. X   FILE *rgbf;
  445. X   int i, items, red, green, blue;
  446. X   char line[512], name[512], *rgbname, *n, *m;
  447. X
  448. X   /* Open the rgb text file.  Abort if error. */
  449. X   if ((rgbf = fopen(rgb_fname, "r")) == NULL)
  450. X      pm_error("error opening rgb text file \"%s\"", rgb_fname, 0, 0, 0, 0);
  451. X
  452. X   /* Loop reading each line in the file. */
  453. X   for (i=0;  fgets(line, sizeof(line), rgbf);  i++) {
  454. X
  455. X       /* Quit if rgb text file is too large. */
  456. X       if (i == MAX_RGBNAMES) {
  457. X          fprintf(stderr,
  458. X             "Too many entries in rgb text file, truncated to %d entries.\n",
  459. X             MAX_RGBNAMES);
  460. X          fflush(stderr);
  461. X          break;
  462. X       }
  463. X
  464. X       /* Read the line.  Skip if bad. */
  465. X       items = sscanf(line, "%d %d %d %[^\n]\n", &red, &green, &blue, name);
  466. X       if (items != 4) {
  467. X          fprintf(stderr, "rgb text file syntax error on line %d\n", i+1);
  468. X          fflush(stderr);
  469. X          i--;
  470. X          continue;
  471. X       }
  472. X
  473. X       /* Make sure rgb values are within 0->255 range.  Skip if bad. */
  474. X       if (red   < 0 || red   > 0xFF ||
  475. X           green < 0 || green > 0xFF ||
  476. X           blue  < 0 || blue  > 0xFF) {
  477. X          fprintf(stderr, "rgb value for \"%s\" out of range, ignoring it\n",
  478. X                  name);
  479. X          fflush(stderr);
  480. X          i--;
  481. X          continue;
  482. X       }
  483. X
  484. X       /* Allocate memory for ascii name.  Abort if error. */
  485. X       if (!(rgbname = (char *) malloc(strlen(name)+1)))
  486. X          pm_error("out of memory allocating rgb name", 0, 0, 0, 0, 0);
  487. X
  488. X       /* Copy string to ascii name and lowercase it. */
  489. X       for (n=name, m=rgbname; *n; n++)
  490. X          *m++ = isupper(*n) ? tolower(*n) : *n;
  491. X       *m = '\0';
  492. X
  493. X       /* Save the rgb values and ascii name in the array. */
  494. X       rgbn[i].r = red   << 8;
  495. X       rgbn[i].g = green << 8;
  496. X       rgbn[i].b = blue  << 8;
  497. X       rgbn[i].name = rgbname;
  498. X   }
  499. X
  500. X   /* Return the max number of rgb names. */
  501. X   *rgbn_max = i-1;
  502. X
  503. X   fclose(rgbf);
  504. X
  505. X} /* read_rgb_names */
  506. X
  507. X/*---------------------------------------------------------------------------*/
  508. X/* Given a number and a base, (base == HIGH_CHAR-LOW_CHAR+1), this routine
  509. X   prints the number into a malloc'ed string and returns it.  The length of
  510. X   the string is specified by "digits".  The ascii characters of the printed
  511. X   number range from LOW_CHAR to HIGH_CHAR.  The string is LOW_CHAR filled,
  512. X   (e.g. if LOW_CHAR==0, HIGH_CHAR==1, digits==5, i=3, routine would return
  513. X   the malloc'ed string "00011"). */
  514. Xchar *gen_numstr(i, base, digits)
  515. Xint i, base, digits;
  516. X{
  517. X   char *str, *p;
  518. X   int d;
  519. X
  520. X   /* Allocate memory for printed number.  Abort if error. */
  521. X   if (!(str = (char *) malloc(digits+1)))
  522. X      pm_error("out of memory", 0, 0, 0, 0, 0);
  523. X
  524. X   /* Generate characters starting with least significant digit. */
  525. X   p = str + digits;
  526. X   *p-- = '\0'; /* nul terminate string */
  527. X   while (p >= str) {
  528. X      d = i % base;
  529. X      i /= base;
  530. X      *p-- = (char) ((int) LOW_CHAR + d);
  531. X   }
  532. X
  533. X   return str;
  534. X
  535. X} /* gen_numstr */
  536. X
  537. X/*---------------------------------------------------------------------------*/
  538. X/* This routine generates the character-pixel colormap table. */
  539. Xvoid gen_cmap(chv, ncolors, maxval, map_rgb_names, rgbn, rgbn_max,
  540. X              cmap, charspp)
  541. X/* input: */
  542. Xcolorhist_vector chv;         /* contains rgb values for colormap */
  543. Xint       ncolors;            /* number of entries in colormap */
  544. Xpixval    maxval;             /* largest color value, all rgb values relative
  545. X                                 to this, (pixval == unsigned short) */
  546. Xint       map_rgb_names;      /* == 1 if mapping rgb values to rgb mnemonics */
  547. Xrgb_names rgbn[MAX_RGBNAMES]; /* rgb mnemonics from rgb text file */
  548. Xint       rgbn_max;           /* number of rgb mnemonics in table */
  549. X/* output: */
  550. Xcixel_map cmap[MAXCOLORS];    /* pixel strings and ascii rgb colors */
  551. Xint       *charspp;           /* characters per pixel */
  552. X{
  553. X   int i, j, base, cpp, mval, red, green, blue, r, g, b, matched;
  554. X   char *str;
  555. X
  556. X   /* Figure out how many characters per pixel we'll be using.  Don't want
  557. X      to be forced to link with libm.a, so using a division loop rather than
  558. X      a log function. */
  559. X   base = (int) HIGH_CHAR - (int) LOW_CHAR + 1;
  560. X   for (cpp=0, j=ncolors;  j;  cpp++) j /= base;
  561. X   *charspp = cpp;
  562. X
  563. X   /* Determine how many hex digits we'll be normalizing to if the rgb value
  564. X      doesn't match a color mnemonic. */
  565. X   mval = (int) maxval;
  566. X   if      (mval <= 0x000F) mval = 0x000F;
  567. X   else if (mval <= 0x00FF) mval = 0x00FF;
  568. X   else if (mval <= 0x0FFF) mval = 0x0FFF;
  569. X   else                     mval = 0xFFFF;
  570. X
  571. X   /* Generate the character-pixel string and the rgb name for each colormap
  572. X      entry. */
  573. X   for (i=0; i<ncolors; i++) {
  574. X
  575. X      /* The character-pixel string is simply a printed number in base "base"
  576. X         where the digits of the number range from LOW_CHAR to HIGH_CHAR and
  577. X         the printed length of the number is "cpp". */
  578. X      cmap[i].cixel = gen_numstr(i, base, cpp);
  579. X
  580. X      /* Fetch the rgb value of the current colormap entry. */
  581. X      red   = PPM_GETR(chv[i].color);
  582. X      green = PPM_GETG(chv[i].color);
  583. X      blue  = PPM_GETB(chv[i].color);
  584. X
  585. X      /* If the ppm color components are not relative to 15, 255, 4095, 65535,
  586. X         normalize the color components here. */
  587. X      if (mval != (int) maxval) {
  588. X         red   = (red   * mval) / (int) maxval;
  589. X         green = (green * mval) / (int) maxval;
  590. X         blue  = (blue  * mval) / (int) maxval;
  591. X      }
  592. X
  593. X      /* If the "-rgb <rgbfile>" option was specified, attempt to map the
  594. X         rgb value to a color mnemonic. */
  595. X      if (map_rgb_names) {
  596. X
  597. X         /* The rgb values of the color mnemonics are normalized relative
  598. X            to 255 << 8, (i.e. 0xFF00).  [That's how the original MIT code
  599. X            did it, really should have been "v * 65535 / 255" instead of
  600. X            "v << 8", but have to use the same scheme here or else colors
  601. X            won't match...]  So, if our rgb values aren't already 16-bit
  602. X            values, need to shift left. */ 
  603. X         if      (mval==0x000F) { r=red << 12;  g=green << 12;  b=blue << 12;
  604. X                                  /* Special case hack for "white". */
  605. X                                  if (0xF000 == r && r == g && g == b)
  606. X                                     r = g = b = 0xFF00;
  607. X                                                                             }
  608. X         else if (mval==0x00FF) { r=red <<  8;  g=green <<  8;  b=blue <<  8;}
  609. X         else if (mval==0x0FFF) { r=red <<  4;  g=green <<  4;  b=blue <<  4;}
  610. X         else                   { r=red;        g=green;        b=blue;      }
  611. X
  612. X         /* Just perform a dumb linear search over the rgb values of the color
  613. X            mnemonics.  One could speed things up by sorting the rgb values
  614. X            and using a binary search, or building a hash table, etc... */
  615. X         for (matched = 0, j=0; j <= rgbn_max; j++)
  616. X             if (r == rgbn[j].r && g == rgbn[j].g && b == rgbn[j].b) {
  617. X
  618. X                /* Matched.  Allocate string, copy mnemonic, and exit. */
  619. X                if (!(str = (char *) malloc(strlen(rgbn[i].name)+1)))
  620. X                   pm_error("out of memory", 0, 0, 0, 0, 0);
  621. X                strcpy(str, rgbn[j].name);
  622. X                cmap[i].rgbname = str;
  623. X                matched = 1;
  624. X                break;
  625. X             }
  626. X         if (matched) continue;
  627. X      }
  628. X
  629. X      /* Either not mapping to color mnemonics, or didn't find a match.
  630. X         Generate an absolute #RGB value string instead. */
  631. X      if (!(str = (char *) malloc(mval == 0x000F ?  5 :
  632. X                                  mval == 0x00FF ?  8 :
  633. X                                  mval == 0x0FFF ? 11 :
  634. X                                                   14)))
  635. X         pm_error("out of memory", 0, 0, 0, 0, 0);
  636. X
  637. X      sprintf(str, mval == 0x000F ? "#%X%X%X"       :
  638. X                   mval == 0x00FF ? "#%02X%02X%02X" :
  639. X                   mval == 0x0FFF ? "#%03X%03X%03X" :
  640. X                                    "#%04X%04X%04X", red, green, blue);
  641. X      cmap[i].rgbname = str;
  642. X   }
  643. X
  644. X} /* gen_cmap */
  645. END_OF_FILE
  646. if test 14877 -ne `wc -c <'ppmtoxpm.c'`; then
  647.     echo shar: \"'ppmtoxpm.c'\" unpacked with wrong size!
  648. fi
  649. # end of 'ppmtoxpm.c'
  650. fi
  651. echo shar: End of archive 1 \(of 1\).
  652. cp /dev/null ark1isdone
  653. MISSING=""
  654. for I in 1 ; do
  655.     if test ! -f ark${I}isdone ; then
  656.     MISSING="${MISSING} ${I}"
  657.     fi
  658. done
  659. if test "${MISSING}" = "" ; then
  660.     echo You have the archive.
  661.     rm -f ark[1-9]isdone
  662. else
  663.     echo You still need to unpack the following archives:
  664.     echo "        " ${MISSING}
  665. fi
  666. ##  End of shell archive.
  667. exit 0
  668.  
  669.